//      gui.c
//      
//      Copyright 2011 DJ Shaji <djshaji@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.


#include "gui.h"

void _x_gui_download_callback ( goffset current, goffset total, XGui * gui )
{
	if ( current == 0 || total == 0 )
	{
		//gtk_progress_bar_pulse ( gui -> bar2 ) ;
		gtk_progress_bar_pulse ( gui -> bar ) ;
	}
	else
	
		gtk_progress_bar_set_fraction ( gui -> bar, ( gfloat ) current / ( gfloat ) total ) ;
	
	while ( gtk_events_pending ())
		gtk_main_iteration_do ( 1 ) ;
}

gchar * x_gui_get_url_contents ( XGui * gui, gchar * url )
{
	GFile * f1 = g_file_new_for_uri ( url ) ;
	XGuiFile * xfile /* heh */ = g_slice_new ( XGuiFile ) ;
	
	xfile -> file_is_loading = TRUE ;
	xfile -> gui = gui ;
	
	g_file_load_contents_async ( f1, gui -> cancellable, x_gui_file_ready, xfile ) ;
	gint u = 0 ;
	
	while ( xfile -> file_is_loading )
	{
		gchar * message = NULL ;
		switch ( u )
		{
			case 0:
				message = g_strdup_printf ( "Resolving %s", url ) ;
				break ;
			case 1:
				message = g_strdup_printf ( "Resolving %s .", url ) ;
				break ;
			case 2:
				message = g_strdup_printf ( "Resolving %s ..", url ) ;
				break ;
			case 3:
				message = g_strdup_printf ( "Resolving %s ...", url ) ;
				break ;
			case 4:
				message = g_strdup_printf ( "Resolving %s ....", url ) ;
				break ;
			case 5:
				message = g_strdup_printf ( "Resolving %s .....", url ) ;
				break ;
			default:
				message = g_strdup_printf ( "Resolving %s ......", url ) ;
				u = 0 ;
		}
		
		x_gui_set_status ( gui, message ) ;
		g_free ( message ) ;
		
		while ( gtk_events_pending ())
			gtk_main_iteration_do ( TRUE ) ;
			
		gtk_progress_bar_pulse ( gui -> bar ) ;
		g_usleep ( 100000 ) ;
		
		if ( g_cancellable_is_cancelled ( gui -> cancellable ))
		{
			//g_cancellable_reset ( gui -> cancellable ) ;
			gtk_widget_set_sensitive ( gui -> cancel, FALSE ) ;
			
			x_gui_set_status ( gui, "Stopped." ) ;
			return NULL ;
		}
		
		u ++ ;
	}
	
	gchar * contents = NULL ;
	gint length = 0 ;
	
	GError * error = NULL ;
	
	g_file_load_contents_finish ( f1, xfile -> result, & contents, & length, 
									NULL, & error ) ;
	g_slice_free ( XGuiFile, xfile ) ;
	
	if ( error )
	{
		x_gui_set_status ( gui, error -> message ) ;
		g_object_unref ( f1 ) ;
		
		return NULL ;
	}
	
	g_object_unref ( f1 ) ;
	return contents ;
}

void x_gui_download ( XGui * gui )
{
	if ( gtk_entry_get_text_length ( gui -> url ) == 0 )
	{
		x_gui_set_status ( gui, "No URL entered !" ) ;
		return ;
	}
	
	gtk_tree_store_clear ( gui -> store ) ;
	
	gtk_widget_set_sensitive ( gui -> cancel, 1 ) ;
	x_gui_set_status ( gui, "Looking up host ..." ) ;
	
	gchar * contents = x_gui_get_url_contents ( gui, gtk_entry_get_text ( gui -> url )) ;
	if ( contents == NULL )
		return ;
	
	while ( gtk_events_pending ())
		gtk_main_iteration () ;

	x_gui_set_status ( gui, "Setting up links ..." ) ;
	x_gui_urls_append_from_text ( gui -> store, NULL, contents, gtk_entry_get_text ( gui -> file_types ), gtk_spin_button_get_value_as_int ( gui -> recurse ), gui ) ;
	
	g_free ( contents ) ;
	
	/**
	gchar * folder = gtk_file_chooser_get_current_folder ( gui -> file_chooser ) ;
	gtk_progress_bar_set_fraction ( gui -> bar, 0.1 ) ;
	
	len = g_list_length ( new_list ) ;
	for ( i = 0 ; i < len ; i ++ )
	{
		if ( g_cancellable_is_cancelled ( gui -> cancellable ))
			break ;
		
		gchar * url = g_list_nth_data ( new_list, i ) ;
		gchar * basename = g_path_get_basename ( url ) ;
		
		gchar * m = g_strdup_printf ( "Downloading %s ...", basename ) ;
		x_gui_set_status ( gui, m ) ;
		
		g_free ( m ) ;
		
		gtk_progress_bar_set_fraction ( gui -> bar2, ( gfloat ) i / ( gfloat ) len ) ;
		
		while ( gtk_events_pending ())
			gtk_main_iteration () ;
		
		GFile * f1 = g_file_new_for_uri ( url ) ;
		
		gchar * filename = g_build_filename ( folder, basename, NULL ) ;
		GFile * f2 = g_file_new_for_path ( filename ) ;
		
		GError * error = NULL ;
		g_file_copy ( f1, f2, G_FILE_COPY_OVERWRITE, gui -> cancellable,
					  _x_gui_download_callback, gui, & error ) ;
		
		if ( error )
			x_gui_set_status ( gui, error -> message ) ;
			
		g_free ( basename ) ;
		g_free ( filename ) ;
		
		g_object_unref ( f1 ) ;
		g_object_unref ( f2 ) ;
		
	}
	
	g_list_foreach ( new_list, g_free, NULL ) ;
	g_list_free ( new_list ) ;
	*/
	
	gtk_widget_set_sensitive ( gui -> cancel, 0 ) ;
	gtk_progress_bar_set_fraction ( gui -> bar2, 1.0 ) ;

	x_gui_set_status ( gui, "Done." ) ;
	g_cancellable_reset ( gui -> cancellable ) ;

	x_gui_find_duplicates ( gui -> store ) ;
}

void x_gui ( void )
{
	GtkDialog * dialog = gtk_dialog_new_with_buttons ( "super X Downloader",
														NULL,
														GTK_DIALOG_MODAL,
														NULL ) ;
	
	gtk_dialog_set_has_separator ( dialog, 0 ) ;
	
	GtkNotebook * book = gtk_notebook_new () ;
	gtk_box_pack_start ( dialog -> vbox, book, 1, 1, 5 ) ;
	
	GtkBox * box = gtk_vbox_new ( 0, 2 ) ;
	gtk_notebook_append_page ( book, box, gtk_label_new ( "Downloader" )) ;
	
	GtkBox * b1 = gtk_hbox_new ( 0, 4 ) ;
	GtkEntry * entry = gtk_entry_new () ;
	
	gtk_box_pack_start ( b1, gtk_label_new ( "Enter URL :" ), 0, 0, 5 ) ;
	gtk_box_pack_start ( b1, entry, 1, 1, 2 ) ;
	
	gtk_box_pack_start ( box, b1, 0, 0, 2 ) ;
	
	GtkButton * go = gtk_button_new_from_stock ( "Go" ) ;
	gtk_box_pack_start ( b1, go, 0, 0, 2 ) ;
	
	GtkBox * b2 = gtk_hbox_new ( 0, 2 ) ;
	
	//gtk_box_pack_start ( box, gtk_hseparator_new (), 0, 0, 2 ) ;
	gtk_box_pack_start ( box, b2, 0, 0, 2 ) ;
	
	gtk_box_pack_start ( b2, gtk_label_new ( "File types:" ), 0, 0, 5 ) ;
	
	GtkEntry * entry2 = gtk_entry_new () ;
	gtk_box_pack_start ( b2, entry2, 1, 1, 2 ) ;
	
	GtkSpinButton * spin = gtk_spin_button_new_with_range ( 0.0, 100.0, 1.0 ) ;
	gtk_box_pack_start ( b2, gtk_label_new ( "Depth :" ), 0, 0, 4 ) ;
	
	gtk_box_pack_start ( b2, spin, 0, 0, 2 ) ;
	
	GtkButton * cancel = gtk_button_new_with_label ( "Cancel" ) ;
	gtk_box_pack_start ( b2, cancel, 0, 0, 4 ) ;
	
	gtk_widget_set_sensitive ( cancel, 0 ) ;
	
	GtkBox * b3 = gtk_hbox_new ( 0, 2 ) ;
	gtk_box_pack_start ( box, b3, 0, 0, 2 ) ;
	
	gtk_box_pack_start ( b3, gtk_label_new ( "Output folder :" ), 0, 0, 5 ) ;
	
	GtkFileChooserButton * choose = gtk_file_chooser_button_new ( "Choose folder", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ) ;
	gtk_box_pack_start ( b3, choose, 1, 1, 2 ) ;
	
	gtk_file_chooser_set_current_folder ( choose, g_get_home_dir ()) ;
	
	GtkFrame * f = gtk_frame_new ( NULL ) ;
	GtkTextView * view = gtk_tree_view_new () ;
	
	GtkTreeStore * store = gtk_tree_store_new ( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ) ;
	gtk_tree_view_set_model ( view, store ) ;
	
	GtkScrolledWindow * sw = gtk_scrolled_window_new ( NULL, NULL ) ;
	gtk_container_add ( sw, view ) ;
	
	gtk_box_pack_start ( box, f, 1, 1, 2 ) ;
	gtk_container_add ( f, sw ) ;
	
	GtkCellRendererText * r1 = gtk_cell_renderer_text_new () ;
	GtkCellRendererToggle * t = gtk_cell_renderer_toggle_new () ;
	
	GtkTreeViewColumn * col1 = gtk_tree_view_column_new_with_attributes ( "Url",
																		r1,
																		"text",
																		0,
																		NULL ),
					* col2 = gtk_tree_view_column_new_with_attributes ( "Done",
																		t,
											
																		NULL ) ;
	gtk_cell_renderer_toggle_set_radio ( t, 0 ) ;
	gtk_tree_view_column_set_attributes ( col2, t, "active", 2 ) ;
	
	gtk_tree_view_append_column ( view, col1 ) ;
	gtk_tree_view_append_column ( view, col2 ) ;
							
	gtk_tree_view_column_set_max_width ( col1, 400 ) ;
	gtk_scrolled_window_set_policy ( sw, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ) ;
	
	GtkWidget * b4 = gtk_hbox_new ( 0, 2 ) ;
	gtk_box_pack_start ( box, b4, 0, 0, 2 ) ;
	
	GtkProgressBar * bar = gtk_progress_bar_new () ;
	gtk_box_pack_start ( b4, bar, 1, 1, 4 ) ;
	
	GtkProgressBar * bar2 = gtk_progress_bar_new () ;
	gtk_box_pack_start ( b4, bar2, 0, 0, 2 ) ;
	
	GtkStatusbar * statusbar = gtk_statusbar_new () ;
	gtk_box_pack_start ( box, statusbar, 0, 0, 2 ) ;
	
	XGui * gui = g_slice_new ( XGui ) ;
	gui -> dialog = dialog ;
	
	gui -> bar = bar ;
	gui -> view = view ;
	
	gui -> recurse = spin ;
	
	gui -> bar2 = bar2 ;
	gui -> store = store ;

	gui -> url = entry ;
	gui -> file_types = entry2 ;
	
	gui -> notebook = book ;
	gui -> file_chooser = choose ;
	
	gui -> cancel = cancel ;
	gui -> statusbar = statusbar ;
	
	gui -> cancellable = g_cancellable_new () ;
	
	g_signal_connect_swapped ( go, "clicked", x_gui_download, gui ) ;
	g_signal_connect_swapped ( cancel, "clicked", g_cancellable_cancel, gui -> cancellable ) ;
	
	g_signal_connect_swapped ( gui -> cancellable, "cancelled", _x_gui_cancel_desensitize, cancel ) ;
	
	g_signal_connect_swapped ( entry, "activate", gtk_button_clicked, go ) ;
	g_signal_connect_swapped ( entry2, "activate", gtk_button_clicked, go ) ;
	
	GtkButton * d = gtk_button_new_with_label ( "Download" ) ;
	g_signal_connect_swapped ( d, "clicked", x_gui_download_files, gui ) ;
	
	gtk_box_pack_start ( dialog -> action_area, d, 0, 0, 2 ) ;
	gtk_dialog_add_button ( dialog, "Exit", 0 ) ;
	
	gtk_window_resize ( dialog, 550, 450 ) ;
	gtk_widget_grab_focus ( entry ) ;
	
	gtk_widget_show_all ( dialog ) ;
	gtk_dialog_run ( dialog ) ;
	
	gtk_widget_destroy ( dialog ) ;
}
	
	
void x_gui_set_status ( XGui * gui, gchar * message )
{
	gtk_statusbar_push ( gui -> statusbar,
						gtk_statusbar_get_context_id ( gui -> statusbar, message ),
						message ) ;
}

void _x_gui_cancel_desensitize ( GtkWidget * cancel )
{
	gtk_widget_set_sensitive ( cancel, 0 ) ;
}

void x_gui_recurse ( XGui * gui, GList * old_list, GList * new_list )
{
	gint i = 0, len = g_list_length ( old_list ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		gchar * url = g_list_nth_data ( old_list, i ) ;
		gchar * text = x_gui_get_url_contents ( gui, url ) ;
		
		if ( text == NULL )
			continue ;
		
		GList * list = x_get_urls ( text ) ;
		GString * s = g_string_new ( NULL ) ;
		
		gchar * id = gtk_entry_get_text ( gui -> file_types ) ;
		gchar ** vector = g_strsplit ( id, ",", -1 ) ;
		
		gint i = 0, len = g_list_length ( list ) ;
		for ( i = 0 ; i < len ; i ++ )
		{
			gchar * path = g_list_nth_data ( list, i ) ;
			
			gint j = 0 ;
			while ( vector [j] != NULL )
			{
				if ( g_strrstr ( path, vector [j] ))
				{
					g_string_append_printf ( s, "[url] %s\n", path ) ;
					new_list = g_list_append ( new_list, g_strdup ( path )) ;
					
					break ;
				}
				
				j ++ ;
			}
		}
		
		g_strfreev ( vector ) ;
		g_string_free ( s, TRUE ) ;
		
		g_list_foreach ( list, g_free, NULL ) ;
		g_list_free ( list ) ;
		
		g_free ( text ) ;
	}
}

void x_gui_urls_append_from_text ( GtkTreeStore * store, GtkTreeIter * parent, gchar * text, gchar * pattern, gint recurse, XGui * gui )
{
	GList * list = x_get_urls ( text ) ;
	if ( list == NULL )
		return ;
	
	gchar ** vector = g_strsplit ( pattern, ",", -1 ) ;
	gint len2 = 0 ;
	
	while ( vector [len2] != NULL )
	{
		g_strstrip ( vector [len2] ) ;
		len2 ++ ;
	}
	
	gint i = 0, len = g_list_length ( list ), u = 0 ;
	for ( i = 0 ; i < len ; i ++ )
	{
		gchar * path = g_list_nth_data ( list, i ) ;

		if ( g_cancellable_is_cancelled ( gui -> cancellable ))
			break ;

		for ( u = 0 ; u < len2 ; u ++ )
		{
			if ( g_cancellable_is_cancelled ( gui -> cancellable ))
				break ;
			
			if ( strstr ( path, vector [u] ))
			{
				GtkTreeIter iter ;
				gtk_tree_store_append ( store, & iter, parent ) ;
				
				gchar * basename = g_path_get_basename ( path ) ;
				
				gtk_tree_store_set ( store, & iter, 0, basename, 1, path, 2, FALSE, -1 ) ;
				g_free ( basename ) ;
			}
			
		}
	}
	
	g_strfreev ( vector ) ;
	
	gchar * xurl = gtk_entry_get_text ( gui -> url ) ;
	
	if ( recurse )
	{
		gint i = 0, len = g_list_length ( list ) ;
		for ( i = 0 ; i < len ; i ++ )
		{
			if ( g_cancellable_is_cancelled ( gui -> cancellable ))
				break ;
			
			gchar * path = g_list_nth_data ( list, i ) ;
			if ( strstr ( path, xurl ) == NULL )
				continue ;
			else if ( g_strcmp0 ( path, xurl ) == 0 )
				continue ;
			
			g_debug ( "%d %s", i, path ) ;
			
			gtk_progress_bar_set_fraction ( gui -> bar2, ( gfloat ) i / ( gfloat ) len ) ;
			
			gtk_widget_set_sensitive ( gui -> cancel, 1 ) ;
			x_gui_set_status ( gui, "Recurse | Looking up host ..." ) ;
			
			while ( gtk_events_pending ())
				gtk_main_iteration () ;
		
			gchar * text = x_gui_get_url_contents ( gui, path ) ;
			if ( text == NULL )
				continue ;
			
			x_gui_set_status ( gui, "Recurse | Setting up links ..." ) ;
			x_gui_urls_append_from_text ( gui -> store, NULL, text, pattern, recurse -1, gui ) ;
			
			while ( gtk_events_pending ())
				gtk_main_iteration () ;
		
			g_free ( text ) ;
		}
	}
	
	g_list_foreach ( list, g_free, NULL ) ;
	g_list_free ( list ) ;

}

void x_gui_download_files ( XGui * gui )
{
	gchar * folder = gtk_file_chooser_get_current_folder ( gui -> file_chooser ) ;
	gtk_progress_bar_set_fraction ( gui -> bar, 0.1 ) ;
	
	gint i = 0, len = gtk_tree_model_iter_n_children ( gui -> store, NULL ) ;
	if ( len == 0 )
	{
		x_gui_set_status ( gui, "Load some files first." ) ;
		return ;
	}
	
	gtk_widget_set_sensitive ( gui -> cancel, 1 ) ;
	//x_gui_find_duplicates ( gui -> store ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		if ( g_cancellable_is_cancelled ( gui -> cancellable ))
			break ;
		
		GtkTreeIter iter ;
		gtk_tree_model_iter_nth_child ( gui -> store, & iter, NULL, i ) ;
		
		gchar * url = NULL ;
		gtk_tree_model_get ( gui -> store, & iter, 1, & url, -1 ) ;
		
		gchar * basename = g_path_get_basename ( url ) ;
		
		gchar * m = g_strdup_printf ( "Downloading %s ...", basename ) ;
		x_gui_set_status ( gui, m ) ;
		
		g_free ( m ) ;
		
		gtk_progress_bar_set_fraction ( gui -> bar2, ( gfloat ) i / ( gfloat ) len ) ;
		
		while ( gtk_events_pending ())
			gtk_main_iteration () ;
		
		GFile * f1 = g_file_new_for_uri ( url ) ;
		
		gchar * filename = g_build_filename ( folder, basename, NULL ) ;
		GFile * f2 = g_file_new_for_path ( filename ) ;
		
		GError * error = NULL ;
		g_file_copy ( f1, f2, G_FILE_COPY_OVERWRITE, gui -> cancellable,
					  _x_gui_download_callback, gui, & error ) ;
		
		if ( error )
			x_gui_set_status ( gui, error -> message ) ;
		else
			gtk_tree_store_set ( gui -> store, & iter, 2, TRUE, -1 ) ;
		
		g_free ( basename ) ;
		g_free ( filename ) ;
		
		g_object_unref ( f1 ) ;
		g_object_unref ( f2 ) ;
		
		g_free ( url ) ;
	}
	
	g_cancellable_reset ( gui -> cancellable ) ;
}	

void x_gui_find_duplicates ( GtkTreeStore * store )
{
	gint i = 0, j = 0, len = gtk_tree_model_iter_n_children ( store, NULL ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		GtkTreeIter iter ;
		if ( ! gtk_tree_model_iter_nth_child ( store, & iter, NULL, i ))
			continue ;
		
		gchar * path ;
		gtk_tree_model_get ( store, & iter, 0, & path, -1 ) ;
		
		for ( j = i ; j < len ; j ++ )
		{
			GtkTreeIter iter1 ;
			if ( ! gtk_tree_model_iter_nth_child ( store, & iter1, NULL, j ))
				continue ;
			
			gchar * path1 = NULL ;
			gtk_tree_model_get ( store, & iter1, 0, & path1, -1 ) ;
			
			if ( g_strcmp0 ( path, path1 ) == 0 )
			{
				gtk_tree_store_remove ( store, & iter1 ) ;
				g_debug ( "Removed %s as duplicate", path1 ) ;
			}
			
			g_free ( path1 ) ;
		}
		
		g_free ( path ) ;
	}
	
}

void x_gui_file_ready ( GObject * source, GAsyncResult * result, XGuiFile * gui )
{
	gui -> file_is_loading = FALSE ;
	gui -> result = g_object_ref ( result ) ;
}
